﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;

namespace GpuProgramCompiler.Compilers
{
	static class Helpers
	{
        static public void ExecuteFXC(String inFile, String outFile, String profile, String entryPoint, bool enableDebugInfo, out List<String> stdOut, out List<String> stdErr)
		{
			List<String> fxcStdOut = new List<String>();
			List<String> fxcStdErr = new List<String>();

			Process newProcess = new Process();

			String options = "/E " + entryPoint + " ";

			if (enableDebugInfo)
			{
				options += "/Zi ";
			}

			if (outFile != null)
			{
				options += "/Fo \"" + outFile + "\" ";
			}

			// Setup process
			newProcess.StartInfo.FileName = "fxc";
			newProcess.StartInfo.Arguments = String.Format("{0} /T {1} /nologo /O3 \"{2}\"", options, profile, inFile);
			newProcess.StartInfo.RedirectStandardError = true;
			newProcess.StartInfo.RedirectStandardOutput = true;
			newProcess.StartInfo.UseShellExecute = false;

			// First, generate plain text shader so we can harvest the shader constants
			newProcess.Start();

			String line = newProcess.StandardOutput.ReadLine();
			while (line != null)
			{
				fxcStdOut.Add(line);
				line = newProcess.StandardOutput.ReadLine();
			}

			line = newProcess.StandardError.ReadLine();
			while (line != null)
			{
				fxcStdErr.Add(line);
				line = newProcess.StandardError.ReadLine();
			}

			newProcess.WaitForExit();

			stdOut = fxcStdOut;
			stdErr = fxcStdErr;
		}

		static public void CompileShader(String filename, String profile, String entryPoint, String platform, bool enableDebugInfo, out Byte[] outCode, out String[] outConstants)
        {
            List<String> stdout;
            List<String> stderr;
            String tmpFilename = Path.GetTempFileName();
            Helpers.ExecuteFXC(filename, tmpFilename, profile, entryPoint, enableDebugInfo, out stdout, out stderr);

			outCode = null;
			outConstants = null;

			if (stderr.Count == 0)
			{
				outCode = File.ReadAllBytes(tmpFilename);
                if (platform != null)
					GetConstantTable(tmpFilename, entryPoint, profile, platform, out outConstants);
                else
                    outConstants = null;
			}
			else
			{
				String error = "";
				foreach (String s in stderr)
				{
					error = error + s + "\n";
				}
				throw new Exception(error);
			}
        }

		static public void GetConstantTable(String filename, String entryPoint, String profile, String platform, out String[] shaderConstants)
		{
			// Setup process
			Process newProcess = new Process();
			newProcess.StartInfo.FileName = "DXConstantTableExtract.exe";
			newProcess.StartInfo.Arguments = filename + " " + platform;
			newProcess.StartInfo.RedirectStandardError = true;
			newProcess.StartInfo.RedirectStandardOutput = true;
			newProcess.StartInfo.UseShellExecute = false;

			// First, generate plain text shader so we can harvest the shader constants
			newProcess.Start();
			newProcess.WaitForExit();

			String stderr = newProcess.StandardError.ReadToEnd();

			if (stderr.Length > 0)
			{
				shaderConstants = null;
				throw new Exception(stderr);
			}

			String stdoutstr = newProcess.StandardOutput.ReadToEnd().Trim();
			if (stdoutstr.Length == 0)
			{
				shaderConstants = null;
			}
			else
			{
				shaderConstants = stdoutstr.Split('\n');
			}
		}
	}
}
